#include<stdio.h>
#include"util.h"
#include"type.h"

static struct type cm_int = {var_int};
static struct type cm_double = {var_double};
static struct type cm_char = {var_char};
static struct type cm_void = {var_void};


struct type* cm_ty_tyint() {return &cm_int;}
struct type* cm_ty_tydouble() {return &cm_double;}
struct type* cm_ty_tychar() {return &cm_char;}
struct type* cm_ty_tyvoid() {return &cm_void;}


struct type* cm_Struct(struct fieldlist* fList)
{
	struct type* ptr = (struct type*)sec_malloc(sizeof(struct type));
	ptr->kind = var_struct;
	ptr->u.list = fList;

	return ptr;
}
struct type* cm_Array(struct type* arr)
{
	struct type* ptr = (struct type*)sec_malloc(sizeof(struct type));
	ptr->kind = var_array;
	ptr->u.arr = arr;

	return ptr;
}


struct typeList* cm_typeList(struct type* head, struct typeList* tail)
{
	struct typeList* ptr = (struct typeList*)sec_malloc(sizeof(struct typeList));	
	ptr->head = head;
	ptr->next = tail;

	return ptr;
}
struct field* cm_Field(struct symbol* name, struct type* ty)
{
	struct field* ptr = (struct field*)sec_malloc(sizeof(struct field));
	ptr->sym = name;
	ptr->fieldtype = ty;

	return ptr;
}
struct fieldlist* cm_FieldList(struct field* head, struct fieldlist* next)
{
	struct fieldlist* ptr = (struct fieldlist*)sec_malloc(sizeof(struct fieldlist));
	ptr->f = head;
	ptr->next = next;

	return ptr;
}

struct valtypeList* cm_valtypeList(struct valtype* val, struct valtypeList* next)
{
	struct valtypeList* ptr = (struct valtypeList*)sec_malloc(sizeof(struct valtypeList));
	ptr->val = val;
	ptr->next = next;

	return ptr;
}

struct valtype* cm_valtype(struct type* ty)
{
	struct valtype* ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	struct fieldlist* s = NULL;
	ptr->ty = ty;
	
	if(ptr->ty->kind == var_struct){
		ptr->u.list = NULL;
		s = ptr->ty->u.list;
		while(s){
			ptr->u.list = cm_valfieldlist(s->f, ptr->u.list);
			s = s->next;
		}
	}
	return ptr;
}

//暂时没有处理二维数组的问题
struct valtype* cm_valarray(struct type* ty, int size)
{
	int i = 0;
	struct fieldlist* s = NULL;
	struct valtype* ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = ty;
	ptr->u.arr = (struct valarr*)sec_malloc(sizeof(struct valarr));
	ptr->u.arr->size = size;
	ptr->u.arr->val = (struct valtype*)sec_malloc(size * sizeof(struct valtype));
	for(i=0;i<size;i++){
		ptr->u.arr->val[i].ty = ty->u.arr;
		if(ty->u.arr->kind == var_struct){
			ptr->u.arr->val[i].u.list = NULL;
			s = ty->u.arr->u.list;
			while(s){
				ptr->u.arr->val[i].u.list = cm_valfieldlist(s->f, ptr->u.arr->val[i].u.list);
				s = s->next;
			}
		}
	}

	return ptr;
}

struct valfieldlist* cm_valfieldlist(struct field* f, struct valfieldlist* n)
{
	struct valfieldlist* ptr = (struct valfieldlist*)sec_malloc(sizeof(struct valfieldlist));
	ptr->next = n;
	ptr->vf = (struct valfield*)sec_malloc(sizeof(struct valfield));//释放内存的时候要特别小心
	ptr->vf->sym = f->sym;
	ptr->vf->ft = cm_valtype(f->fieldtype);
	return ptr;
}

void showValue(struct valtype* var)
{
	struct valfieldlist* s = NULL;
	switch(var->ty->kind){
		case var_int:
			printf("int %d\n",var->u.i);
		break;
		case var_char:
			printf("char %c\n",var->u.c);
		break;
		case var_double:
			printf("double %lf\n",var->u.d);
		break;
		case var_struct:
			printf("struct\n");
			s = var->u.list;
			while(s!=NULL){
				showfieldvalue(s->vf);
				s = s->next;
			}
			printf("end struct\n");
		break;
		default:
			printf("not spport to print.\n");
	}
}

void showfieldvalue(struct valfield* vf)
{
	if(vf == NULL)
		return;
	printf("field %s: ",vf->sym->name);
	showValue(vf->ft);
}

struct valtype* plus_val(struct valtype* lhs, struct valtype* rhs)
{
	struct valtype* ptr = NULL;
	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct plus.\n");
		return NULL;
	}
	ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = lhs->ty;
	switch(lhs->ty->kind){
		case var_int:
				ptr->u.i = lhs->u.i + toInt(rhs);
				break;
		case var_double:
				ptr->u.d = lhs->u.d + toDouble(rhs);
				break;
		case var_char:
				ptr->u.c = lhs->u.c + toChar(rhs);
				break;
		default:
			printf("unknown type.\n");
	}
	return ptr;
}
struct valtype* minus_val(struct valtype* lhs, struct valtype* rhs)
{
	struct valtype* ptr = NULL;
	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct minus.\n");
		return NULL;
	}
	ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = lhs->ty;
	switch(lhs->ty->kind){
		case var_int:
				ptr->u.i = lhs->u.i - toInt(rhs);
				break;
		case var_double:
				ptr->u.d = lhs->u.d - toDouble(rhs);
				break;
		case var_char:
				ptr->u.c = lhs->u.c - toChar(rhs);
				break;
		default:
			printf("unknown type.\n");
	}
	return ptr;
}
struct valtype* mul_val(struct valtype* lhs, struct valtype* rhs)
{
	struct valtype* ptr = NULL;
	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct mul.\n");
		return NULL;
	}
	ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = lhs->ty;
	switch(lhs->ty->kind){
		case var_int:
				ptr->u.i = lhs->u.i * toInt(rhs);
				break;
		case var_double:
				ptr->u.d = lhs->u.d * toDouble(rhs);
				break;
		case var_char:
				ptr->u.c = lhs->u.c * toChar(rhs);
				break;
		default:
			printf("unknown type.\n");
	}
	return ptr;
}
struct valtype* div_val(struct valtype* lhs, struct valtype* rhs)
{
	struct valtype* ptr = NULL;
	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct div.\n");
		return NULL;
	}
	ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = lhs->ty;
	switch(lhs->ty->kind){
		case var_int:
				ptr->u.i = lhs->u.i / toInt(rhs);
				break;
		case var_double:
				ptr->u.d = lhs->u.d / toDouble(rhs);
				break;
		case var_char:
				ptr->u.c = lhs->u.c / toChar(rhs);
				break;
		default:
			printf("unknown type.\n");
	}
	return ptr;
}

//小于
struct valtype* val_cmp_Less(struct valtype* lhs, struct valtype* rhs)
{
	struct valtype* ptr = NULL;
	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct cmp.\n");
		return NULL;
	}
	ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = cm_ty_tyint();
	switch(lhs->ty->kind){
		case var_int:
				ptr->u.i = (lhs->u.i < toInt(rhs));
				break;
		case var_double:
				ptr->u.i = (lhs->u.d < toDouble(rhs));
				break;
		case var_char:
				ptr->u.i = (lhs->u.c < toChar(rhs));
				break;
		default:
			printf("unknown type.\n");
	}
	return ptr;
}

//小于等于
struct valtype* val_cmp_LessOrEqual(struct valtype* lhs, struct valtype* rhs)
{
	struct valtype* ptr = NULL;
	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct cmp.\n");
		return NULL;
	}
	ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = cm_ty_tyint();
	switch(lhs->ty->kind){
		case var_int:
				ptr->u.i = (lhs->u.i <= toInt(rhs));
				break;
		case var_double:
				ptr->u.i = (lhs->u.d <= toDouble(rhs));
				break;
		case var_char:
				ptr->u.i = (lhs->u.c <= toChar(rhs));
				break;
		default:
			printf("unknown type.\n");
	}
	return ptr;
}

//等于
struct valtype* val_cmp_Equal(struct valtype* lhs, struct valtype* rhs)
{
	struct valtype* ptr = NULL;
	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct cmp.\n");
		return NULL;
	}
	ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = cm_ty_tyint();
	switch(lhs->ty->kind){
		case var_int:
				ptr->u.i = (lhs->u.i == toInt(rhs));
				break;
		case var_double:
				ptr->u.i = (lhs->u.d == toDouble(rhs));
				break;
		case var_char:
				ptr->u.i = (lhs->u.c == toChar(rhs));
				break;
		default:
			printf("unknown type.\n");
	}
	return ptr;
}

//大于
struct valtype* val_cmp_Greater(struct valtype* lhs, struct valtype* rhs)
{
	struct valtype* ptr = NULL;
	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct cmp.\n");
		return NULL;
	}
	ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = cm_ty_tyint();
	switch(lhs->ty->kind){
		case var_int:
				ptr->u.i = (lhs->u.i > toInt(rhs));
				break;
		case var_double:
				ptr->u.i = (lhs->u.d > toDouble(rhs));
				break;
		case var_char:
				ptr->u.i = (lhs->u.c > toChar(rhs));
				break;
		default:
			printf("unknown type.\n");
	}
	return ptr;
}

//大于等于
struct valtype* val_cmp_GreaterOrEqual(struct valtype* lhs, struct valtype* rhs)
{
	struct valtype* ptr = NULL;
	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct cmp.\n");
		return NULL;
	}
	ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = cm_ty_tyint();
	switch(lhs->ty->kind){
		case var_int:
				ptr->u.i = (lhs->u.i >= toInt(rhs));
				break;
		case var_double:
				ptr->u.i = (lhs->u.d >= toDouble(rhs));
				break;
		case var_char:
				ptr->u.i = (lhs->u.c >= toChar(rhs));
				break;
		default:
			printf("unknown type.\n");
	}
	return ptr;
}

//不等于
struct valtype* val_cmp_NotEqual(struct valtype* lhs, struct valtype* rhs)
{
	struct valtype* ptr = NULL;
	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct cmp.\n");
		return NULL;
	}
	ptr = (struct valtype*)sec_malloc(sizeof(struct valtype));
	ptr->ty = cm_ty_tyint();
	switch(lhs->ty->kind){
		case var_int:
				ptr->u.i = (lhs->u.i != toInt(rhs));
				break;
		case var_double:
				ptr->u.i = (lhs->u.d != toDouble(rhs));
				break;
		case var_char:
				ptr->u.i = (lhs->u.c != toChar(rhs));
				break;
		default:
			printf("unknown type.\n");
	}
	return ptr;
}



int toInt(struct valtype* rhs)
{
	switch(rhs->ty->kind){
		case var_int:
			return rhs->u.i;
		case var_double:
			return (int)rhs->u.d;
		case var_char:
			return (int)rhs->u.c;
		default:
			printf("unknown type.\n");
			return 0;
	}
}
double toDouble(struct valtype* rhs)
{
	switch(rhs->ty->kind){
		case var_int:
			return (double)rhs->u.i;
		case var_double:
			return rhs->u.d;
		case var_char:
			return (double)rhs->u.c;
		default:
			printf("unknown type.\n");
			return 0.0;
	}
}
char toChar(struct valtype* rhs)
{
	switch(rhs->ty->kind){
		case var_int:
			return (char)rhs->u.i;
		case var_double:
			return (char)rhs->u.d;
		case var_char:
			return rhs->u.c;
		default:
			printf("unknown type.\n");
			return 0;
	}
}

void assign_val(struct valtype* lhs, struct valtype* rhs)
{

	if(lhs->ty->kind==var_struct || rhs->ty->kind==var_struct)
	{
		printf("not support struct assign.\n");
		return ;
	}
	switch(lhs->ty->kind){
		case var_int:
				lhs->u.i = toInt(rhs);
				break;
		case var_double:
				lhs->u.d = toDouble(rhs);
				break;
		case var_char:
				lhs->u.c = toChar(rhs);
				break;
		default:
			printf("unknown type.\n");
	}
}

struct valtype* convertInt(int i)
{
	struct valtype* ptr = cm_valtype(cm_ty_tyint());
	ptr->u.i = i;
	return ptr;
}
struct valtype* convertDouble(double d)
{
	struct valtype* ptr = cm_valtype(cm_ty_tydouble());
	ptr->u.d = d;
	return ptr;
}
struct valtype* convertChar(char c)
{
	struct valtype* ptr = cm_valtype(cm_ty_tychar());
	ptr->u.c = c;
	return ptr;
}

struct valtype* get_StructField(struct valtype* val, struct symbol* sym)
{
	struct valfieldlist* list = NULL;
	struct valfield* field = NULL;
	if(val->ty->kind != var_struct)
		return NULL;
	list = val->u.list;
	while(list){
		if(list->vf->sym==sym)
			return list->vf->ft;
		list = list->next;
	}
	return NULL;
}
